﻿using System;
using System.Configuration;
using System.Web.Caching;

namespace MvcSupplantCaching
{
    /// <summary>
    /// Class responsible for instantiating an <see cref="BaseOutputCacheProvider"/> based on configuration.
    /// </summary>
    public sealed class OutputCache
    {
        /// <summary>
        /// Used as the key for storing the output cache key of the current request in the RequestCache.
        /// </summary>
        public const string CacheKey = "OutputCacheKey";

        /// <summary>
        /// Used as the key for storing the url for the current output cached page in the RequestCache.
        /// </summary>
        public const string UrlCacheKey = "OutputCachedUrl";

        /// <summary>
        /// Default constructor. Instantiates a new <see cref="OutputCacheProvider"/> based on configuration, or the default if configuration is absent.
        /// </summary>
        static OutputCache()
        {
            DefaultOptions = OutputCacheOptions.None;

            var providerSettings = new CacheSettingsManager().RetrieveOutputCacheProviderSettings();

            if (providerSettings == null || providerSettings.Type == null)
            {
                Instance = new MemoryCacheProvider();
            }
            else
            {
                Type cacheType = Type.GetType(providerSettings.Type);
                if (cacheType == null)
                {
                    throw new ConfigurationErrorsException(string.Format("Unable to instantiate and initialize OutputCacheProvider of type '{0}'. Make sure you are specifying the full type name.",
                        providerSettings.Type));
                }
                try
                {
                    Instance = (BaseOutputCacheProvider)Activator.CreateInstance(cacheType);
                    Instance.Initialize(providerSettings.Name, providerSettings.Parameters);
                }
                catch (Exception ex)
                {
                    throw new ConfigurationErrorsException(
                        string.Format("Unable to instantiate and initialize OutputCacheProvider of type '{0}'. Make sure you are specifying the full type name.", providerSettings.Type),
                        ex
                    );
                }
            }
        }

        private OutputCache()
        {
        }

        /// <summary>
        /// Returns the configured <see cref="OutputCacheProvider"/>
        /// </summary>
        public static BaseOutputCacheProvider Instance
        {
            get;
            private set;
        }

        /// <summary>
        /// Specifies the default value for the <see cref="SupplantOutputCacheAttribute.Options"/>
        /// </summary>
        public static OutputCacheOptions DefaultOptions
        {
            get;
            set;
        }

        private readonly SupplantCache _supplantCache = SupplantCache.Cache;
        private static readonly OutputCache CacheInstance = new OutputCache();

        /// <summary>
        /// The provider for the supplant cache.
        /// </summary>
        public static SupplantCache SupplantProvider { get { return CacheInstance._supplantCache; } }
    }
}
